5850 // Multiprocessor bootstrap.
5851 // Search memory for MP description structures.
5852 // http://developer.intel.com/design/pentium/datashts/24201606.pdf
5853 
5854 #include "types.h"
5855 #include "defs.h"
5856 #include "param.h"
5857 #include "mp.h"
5858 #include "x86.h"
5859 #include "mmu.h"
5860 #include "proc.h"
5861 
5862 struct cpu cpus[NCPU];
5863 static struct cpu *bcpu;
5864 int ismp;
5865 int ncpu;
5866 uchar ioapicid;
5867 
5868 int
5869 mpbcpu(void)
5870 {
5871   return bcpu-cpus;
5872 }
5873 
5874 static uchar
5875 sum(uchar *addr, int len)
5876 {
5877   int i, sum;
5878 
5879   sum = 0;
5880   for(i=0; i<len; i++)
5881     sum += addr[i];
5882   return sum;
5883 }
5884 
5885 // Look for an MP structure in the len bytes at addr.
5886 static struct mp*
5887 mpsearch1(uchar *addr, int len)
5888 {
5889   uchar *e, *p;
5890 
5891   cprintf("mpsearch1 0x%x %d\n", addr, len);
5892   e = addr+len;
5893   for(p = addr; p < e; p += sizeof(struct mp))
5894     if(memcmp(p, "_MP_", 4) == 0 && sum(p, sizeof(struct mp)) == 0)
5895       return (struct mp*)p;
5896   return 0;
5897 }
5898 
5899 
5900 // Search for the MP Floating Pointer Structure, which according to the
5901 // spec is in one of the following three locations:
5902 // 1) in the first KB of the EBDA;
5903 // 2) in the last KB of system base memory;
5904 // 3) in the BIOS ROM between 0xE0000 and 0xFFFFF.
5905 static struct mp*
5906 mpsearch(void)
5907 {
5908   uchar *bda;
5909   uint p;
5910   struct mp *mp;
5911 
5912   bda = (uchar*)0x400;
5913   if((p = ((bda[0x0F]<<8)|bda[0x0E]) << 4)){
5914     if((mp = mpsearch1((uchar*)p, 1024)))
5915       return mp;
5916   } else {
5917     p = ((bda[0x14]<<8)|bda[0x13])*1024;
5918     if((mp = mpsearch1((uchar*)p-1024, 1024)))
5919       return mp;
5920   }
5921   return mpsearch1((uchar*)0xF0000, 0x10000);
5922 }
5923 
5924 // Search for an MP configuration table.  For now,
5925 // don't accept the default configurations (physaddr == 0).
5926 // Check for correct signature, calculate the checksum and,
5927 // if correct, check the version.
5928 // To do: check extended table checksum.
5929 static struct mpconf*
5930 mpconfig(struct mp **pmp)
5931 {
5932   struct mpconf *conf;
5933   struct mp *mp;
5934 
5935   if((mp = mpsearch()) == 0 || mp->physaddr == 0)
5936     return 0;
5937   conf = (struct mpconf*)mp->physaddr;
5938   if(memcmp(conf, "PCMP", 4) != 0)
5939     return 0;
5940   if(conf->version != 1 && conf->version != 4)
5941     return 0;
5942   if(sum((uchar*)conf, conf->length) != 0)
5943     return 0;
5944   *pmp = mp;
5945   return conf;
5946 }
5947 
5948 
5949 
5950 void
5951 mpinit(void)
5952 {
5953   uchar *p, *e;
5954   struct mp *mp;
5955   struct mpconf *conf;
5956   struct mpproc *proc;
5957   struct mpioapic *ioapic;
5958 
5959   bcpu = &cpus[0];
5960   if((conf = mpconfig(&mp)) == 0)
5961     return;
5962   ismp = 1;
5963   lapic = (uint*)conf->lapicaddr;
5964   for(p=(uchar*)(conf+1), e=(uchar*)conf+conf->length; p<e; ){
5965     switch(*p){
5966     case MPPROC:
5967       proc = (struct mpproc*)p;
5968       if(ncpu != proc->apicid) {
5969         cprintf("mpinit: ncpu=%d apicpid=%d", ncpu, proc->apicid);
5970         panic("mpinit");
5971       }
5972       if(proc->flags & MPBOOT)
5973         bcpu = &cpus[ncpu];
5974       cpus[ncpu].id = ncpu;
5975       ncpu++;
5976       p += sizeof(struct mpproc);
5977       continue;
5978     case MPIOAPIC:
5979       ioapic = (struct mpioapic*)p;
5980       ioapicid = ioapic->apicno;
5981       p += sizeof(struct mpioapic);
5982       continue;
5983     case MPBUS:
5984     case MPIOINTR:
5985     case MPLINTR:
5986       p += 8;
5987       continue;
5988     default:
5989       cprintf("mpinit: unknown config type %x\n", *p);
5990       panic("mpinit");
5991     }
5992   }
5993   if(mp->imcrp){
5994     // Bochs doesn't support IMCR, so this doesn't run on Bochs.
5995     // But it would on real hardware.
5996     outb(0x22, 0x70);   // Select IMCR
5997     outb(0x23, inb(0x23) | 1);  // Mask external interrupts.
5998   }
5999 }
